package de.koller.oceanFramework.glyph;

import de.koller.oceanFramework.OceanException;
import de.koller.oceanFramework.gl.util.ParticleTexture;
import de.koller.oceanFramework.gl.util.RasterManager;
import de.koller.oceanFramework.tree.Child;
import de.koller.oceanFramework.tree.Sea3X;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.io.InputStream;
import javax.imageio.ImageIO;
import org.lwjgl.opengl.GL11;

public class GlyphScreenGL extends Sea3X {
	
	private String name;
	private static String loadedPath;
	private static BufferedImage glyphs;
	private final int width, height;
	private ParticleTexture szene;

	private final Glyph clearGlyph = new Glyph( 0xffffffff, 0x00000000, -1, -1 );
	private final Glyph[][] gszene;
	private final Glyph[][] gchanged;
	
	private boolean clearable = true;
	
	@Child private final GlyphRendererGL renderer;
	private boolean automaticBuffering = false;
	
	private int maxFilter = GL11.GL_NEAREST;
	private int minFilter = GL11.GL_LINEAR;
	
	public GlyphScreenGL( int width, int height, IFontValue fv, String fontpath ) {
		this.width = width;
		this.height = height;
		this.gszene = new Glyph[ width/GlyphScreen.GLYPH_WIDTH + 1][ height/GlyphScreen.GLYPH_HEIGHT + 1];
		this.gchanged = new Glyph[ width/GlyphScreen.GLYPH_WIDTH + 1][ height/GlyphScreen.GLYPH_HEIGHT + 1];
		
		this.renderer = new GlyphRendererGL( fv );
		
		try {
			//@todo Nicht static laden sonder in buffer!
			if( glyphs != null )
				if( !fontpath.equals( loadedPath ) )
					throw new OceanException( "only one type of Glyphs can be loaded!" );
				else
					return;
			ClassLoader cl = this.getClass().getClassLoader();
			InputStream in = cl.getResourceAsStream( fontpath );
			loadedPath = fontpath;
			glyphs = ImageIO.read( in );
		} catch ( IOException ex ) {
			throw new OceanException( ex );
		}
	}

	@Override
	protected void init() {
		super.init();
		
		ParticleTexture.MAG_FILTER = maxFilter;
		ParticleTexture.MIN_FILTER = minFilter;
		szene = ParticleTexture.generate( width, height );
	}
	
	@Override
	protected void render( int elapsedTime ) {
		super.render( elapsedTime );
		
		if( automaticBuffering )
			updateBuffer();
	}
	
	public void updateBuffer() {
		szene.bind();
		
		for( int x = 0; x < gszene.length; x++ ) 
			for( int y = 0; y < gszene[0].length; y++ )
				if( gchanged[x][y] == null || !gchanged[x][y].equals( gszene[x][y] ) ) {
					drawGlyph( x, y, gszene[x][y] );
					gchanged[x][y] = gszene[x][y];
				}
		
		if( clearable )
			for( int x = 0; x < gszene.length; x++ ) 
				for( int y = 0; y < gszene[0].length; y++ )
					gszene[x][y] = clearGlyph;
	}
	
	public ParticleTexture getTexture() {
		return szene;
	}

	public void clearGlyph( int x, int y, int color ) {
		Glyph g = new Glyph( 0, color, -1, -1 );
		renderGlyph( x, y, g );
	}
	
	public void renderGlyph( int x, int y, Glyph g ) {
		try {
			if( gszene[x][y] != null && gszene[x][y].equals( g ) )
				return;
		
			gszene[x][y] = g;
		} catch( ArrayIndexOutOfBoundsException ex ) {
			return;
		}
	}
	
	private void drawGlyph( int sx, int sy, Glyph g ) {
		if( g == null )
			return;
		
		RasterManager rm = new RasterManager( GlyphScreen.GLYPH_WIDTH, GlyphScreen.GLYPH_HEIGHT );
		
		for( int x = 0; x < GlyphScreen.GLYPH_WIDTH; x++ )
			for( int y = 0; y < GlyphScreen.GLYPH_HEIGHT; y++ ) {

				int c;
				if( g.getGlyphx() == -1 && g.getGlyphy() == -1 )
					c = g.getBackColor();
				else {
					int sc = glyphs.getRGB( x + g.getGlyphx()*GlyphScreen.GLYPH_WIDTH,
							y + g.getGlyphy()*GlyphScreen.GLYPH_HEIGHT );
					
					//c = sc == 0x00000000 ? g.getBackColor() : g.getFontColor();
					if( sc == 0x00000000 )		c = g.getBackColor();
					else if( sc == 0xff000000 ) c = g.getFontColor();
					else if( sc == 0xff808080 ) c = g.getSecondaryColor();
					else						c = 0xffff0000;
				}
				
				rm.setPixel( c, x, y );
			}
		
		try {
			szene.flush( sx*GlyphScreen.GLYPH_WIDTH, sy*GlyphScreen.GLYPH_HEIGHT, 
					GlyphScreen.GLYPH_WIDTH, GlyphScreen.GLYPH_HEIGHT, rm.getData() );
		} catch( IndexOutOfBoundsException ex ) {
			
		}
	}

	public GlyphRendererGL getRenderer() {
		return renderer;
	}

	public String getName() {
		return name;
	}

	public void setName( String name ) {
		this.name = name;
	}

	public void setClearable( boolean clearable ) {
		this.clearable = clearable;
	}

	public void setAutomaticBuffering( boolean automaticBuffering ) {
		this.automaticBuffering = automaticBuffering;
	}

	public void setMaxFilter( int maxFilter ) {
		this.maxFilter = maxFilter;
	}

	public void setMinFilter( int minFilter ) {
		this.minFilter = minFilter;
	}
	
}
